package org.lgiavedoni.android.franq.core.communication;

import org.lgiavedoni.android.franq.core.command.CommandManager;
import org.lgiavedoni.android.franq.core.exception.ControledFinishException;
import org.lgiavedoni.android.franq.core.message.MessageIn;
import org.lgiavedoni.android.franq.core.message.MessageInterceptor;
import org.lgiavedoni.android.franq.core.message.MessageOut;
import org.lgiavedoni.android.franq.core.speak.CommonPhrase;
import org.lgiavedoni.android.franq.core.speak.CommonPhraseHelper;
import org.lgiavedoni.android.franq.service.communication.CommunicationService;
import org.lgiavedoni.android.franq.service.log.Logger;
import org.lgiavedoni.android.franq.service.message.MessageInterceptorService;
import org.lgiavedoni.android.franq.util.LoopUtil;
import org.lgiavedoni.android.franq.util.date.DateUtil;

public class CommunicationChannel extends Thread implements CommunicationChannelTherad {

	private final CommunicationSource communicationSource;
	private final String user;
	private MessageIn currentMessage;
	private MessageInterceptor activeInterceptor = null;
	private final String COMMUNICATION_FLAG;

	public CommunicationChannel(CommunicationSource communicationSource, String user) {
		super();
		COMMUNICATION_FLAG = "FLAG_" + DateUtil.getTimeInMillis();
		this.communicationSource = communicationSource;
		this.user = user;
	}

	public void reciveMessage(final MessageIn message) {
		this.currentMessage = message;
		synchronized (COMMUNICATION_FLAG) {
			this.COMMUNICATION_FLAG.notifyAll();
		}

	}

	@Override
	public void run() {
		LoopUtil.prepare();
		setName("Communication Channel [User: " + user + ", Source: " + communicationSource.getClass().getSimpleName() + "]");
		try {
			while (true) {

				synchronized (COMMUNICATION_FLAG) {
					if (currentMessage == null && activeInterceptor == null) {
						COMMUNICATION_FLAG.wait();
						continue;
					}

					// If is already in chat with one MessageInterceptor should
					// continue
					if (isBusy()) {

						if (CommunicationService.inst.isStopCommand(currentMessage)) {
							// Check if is a general Message. (stop, not now)

							// TODO should I delay the activeInterceptor
							// activeInterceptor.delay()
							clearMessageInterceptor();
							sendMessage(CommonPhraseHelper.BAD_MOMENT);
							continue;
						}

						// Process the message
						processMessage();
					}

					// Is a specific command
					if (CommandManager.inst.tryToExecuteCommand(currentMessage)) {
						currentMessage = null;
						clearMessageInterceptor();
					} else {

						if (activeInterceptor == null) {
							// If there aren't any interceptor active should
							// find
							// the right
							MessageInterceptor messageInterceptor = MessageInterceptorService.inst.getMessageInterceptor(currentMessage.getText());
							if (messageInterceptor != null) {
								activeInterceptor = messageInterceptor;
								processMessage();
							} else {
								// Message undefined
								sendMessage(CommonPhraseHelper.I_DONT_UNDERSTAND);
							}
						}
					}

					COMMUNICATION_FLAG.wait();
				}
			}

		} catch (Exception ex) {
			Logger.inst.error("Mesage: " + currentMessage, ex);
		}

	}

	public boolean isBusy() {
		return activeInterceptor != null ? true : false;
	}

	public void setMessageInterceptor(MessageInterceptor messageInterceptor) {
		if (isBusy())
			throw new IllegalAccessError("Ther are a activeInterceptor already.");
		activeInterceptor = messageInterceptor;
	}

	public synchronized void clearMessageInterceptor() {
		if (activeInterceptor != null && activeInterceptor.getQuestion() != null) {
			if (!activeInterceptor.getQuestion().isSolved()) {
				activeInterceptor.getQuestion().cancel();
			}
			activeInterceptor.setQuestion(null);
		}
		activeInterceptor = null;
		currentMessage = null;
	}

	private class CommunicatinChannelProcessor extends Thread implements CommunicationChannelTherad {

		@Override
		public void run() {
			LoopUtil.prepare();
			setName("Processing message...");
			try {
				if (activeInterceptor.getQuestion() != null && !activeInterceptor.getQuestion().isSolved()) {
					// Wait for a valid answer
					if (!activeInterceptor.getQuestion().process(currentMessage)) {
						// Do nothing
						// QuestionService.inst.askNowAndWait(interceptor.getQuestion());
						activeInterceptor.getQuestion().ask();
						// The questions was Discarded
						if (activeInterceptor.getQuestion().isDiscarded()) {
							// sendMessage(CommonPhraseHelper.DISCARDED_QUESTION);
							clearMessageInterceptor();
						}
					}
				} else {
					activeInterceptor.processMessage(currentMessage);
					clearMessageInterceptor();
				}
			} catch (ControledFinishException ce) {
				// Do nothing ;)
			} catch (Exception e) {
				// FIXME I should move this to the MessageInterceptor?
				Logger.inst.error(e);
				if (activeInterceptor != null)
					activeInterceptor.fail();
				clearMessageInterceptor();
			}
		}

		@Override
		public CommunicationChannel getChannel() {
			return CommunicationChannel.this;
		}

	}

	private void processMessage() {
		new CommunicatinChannelProcessor().start();
	}

	public void sendMessage(CommonPhrase phrase) {
		try {
			sendDefaultTextMessage(phrase.getValue());
		} catch (Exception e) {
			Logger.inst.error(e);
		}
	}

	public void sendDefaultTextMessage(String message) {
		sendMessage(MessageOut.create(message));
	}

	public void sendMessage(MessageOut message) {
		communicationSource.sendMessage(message);
	}

	@Override
	public CommunicationChannel getChannel() {
		return this;
	}

	public String getUser() {
		return user;
	}

}
